package com.ikas.ai.framework.node;

import com.ikas.ai.framework.core.model.NodeInputVariables;
import com.ikas.ai.framework.node.impl.AbstractNode;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;

import java.util.List;

/**
 * @Description: 执行节点链
 * @Author: qi.yilai
 * @Date: 2023/1/13 13:42
 * @Version: 1.0.0
 **/
public class ChainNode<O> {

    // 当前节点
    private AbstractNode<O> currentNode;

    // 前置节点
    private List<ChainNode> previous = Lists.newArrayList();

    // 后置节点
    private List<ChainNode> next = Lists.newArrayList();

    // 已经故障无法继续执行
    private volatile boolean fatal = false;

    // 是否完成
    private volatile boolean finished = false;

    public ChainNode(AbstractNode<O> currentNode) {
        this.currentNode = currentNode;
    }

    public boolean execute() {
        return currentNode.execute();
    }

    public boolean canExecute() {
        for (ChainNode chainNode : previous) {
            if (!chainNode.isFinished()) {
                return false;
            }
        }
        return true;
    }

    /**
     * 后置节点填充入参
     */
    public void fillPreviousResult() {
        next.forEach(chainNode -> {
            NodeInputVariables variables = currentNode.outVariables();
            chainNode.input(variables);
        });
    }

    /**
     * 节点异常，标记下游的节点故障，无法继续执行
     */
    public void markFatal() {
        for (ChainNode chainNode : next) {
            if (chainNode.isFatal()) {
                continue;
            }
            chainNode.setFatal(true);
            chainNode.markFatal();
        }
    }

    public NodeStatus status() {
        return currentNode.status();
    }

    private void input(NodeInputVariables variables) {
        currentNode.input(variables);
    }

    public boolean appendPrevious(ChainNode<O> chainNode) {
        return previous.add(chainNode);
    }

    public boolean appendNext(ChainNode<O> chainNode) {
        return next.add(chainNode);
    }

    public AbstractNode<O> getCurrentNode() {
        return currentNode;
    }

    public List<ChainNode> getPrevious() {
        return previous;
    }

    public List<ChainNode> getNext() {
        return next;
    }

    public boolean isFatal() {
        return fatal;
    }

    public void setFatal(boolean fatal) {
        this.fatal = fatal;
    }

    public boolean isFinished() {
        return finished;
    }

    public void setFinished(boolean finished) {
        this.finished = finished;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;

        if (o == null || getClass() != o.getClass()) return false;

        ChainNode<?> chainNode = (ChainNode<?>) o;

        return new EqualsBuilder().append(fatal, chainNode.fatal).append(finished, chainNode.finished).append(currentNode, chainNode.currentNode).append(previous, chainNode.previous).append(next, chainNode.next).isEquals();
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder(17, 37).append(currentNode).append(previous).append(next).append(fatal).append(finished).toHashCode();
    }
}
